Hệ thống quản lý phòng khám trực tuyến bằng PHP

1 <?php
2
3 define(
'datalist_filters_count', 20);
4 define(
'datalist_image_uploads_exist', True);
5 define(
'datalist_max_records_multi_selection', 1000);
6 define(
'datalist_max_page_lump', 50);
7 define(
'datalist_max_records_dv_print', 100);
8 define(
'datalist_auto_complete_size', 1000);
9 define(
'datalist_date_separator', '/');
10 define(
'datalist_date_format', 'mdY');
11
12 $curr_dir = dirname(__FILE__);
13 require_once($curr_dir .
'/combo.class.php');
14 require_once($curr_dir .
'/data_combo.class.php');
15 require_once($curr_dir .
'/date_combo.class.php');
16
17 class
DataList{
18     
// this class generates the data table ...
19
20     
var $QueryFieldsTV,
21         $QueryFieldsCSV,
22         $QueryFieldsFilters,
23         $QueryFieldsQS,
24         $QueryFrom,
25         $QueryWhere,
26         $QueryOrder,
27         $filterers,
28
29         $ColWidth,
// array of field widths
30         $DataHeight,
31         $TableName,
32
33         $AllowSelection,
34         $AllowDelete,
35         $AllowMassDelete,
36         $AllowDeleteOfParents,
37         $AllowInsert,
38         $AllowUpdate,
39         $SeparateDV,
40         $Permissions,
41         $AllowFilters,
42         $AllowSavingFilters,
43         $AllowSorting,
44         $AllowNavigation,
45         $AllowPrinting,
46         $HideTableView,
47         $AllowCSV,
48         $CSVSeparator,
49
50         $QuickSearch,
// 0 to 3
51
52         $RecordsPerPage,
53         $ScriptFileName,
54         $RedirectAfterInsert,
55         $TableTitle,
56         $PrimaryKey,
57         $DefaultSortField,
58         $DefaultSortDirection,
59
60         
// Templates variables
61         $Template,
62         $SelectedTemplate,
63         $TemplateDV,
64         $TemplateDVP,
65         $ShowTableHeader,
// 1 = show standard table headers
66         $ShowRecordSlots,
// 1 = show empty record slots in table view
67         $TVClasses,
68         $DVClasses,
69         
// End of templates variables
70
71         $ContentType,
// set by DataList to 'tableview', 'detailview', 'tableview+detailview', 'print-tableview', 'print-detailview' or 'filters'
72         $HTML;
// generated html after calling Render()
73
74     function __construct(){
// PHP 7 compatibility
75         $
this->DataList();
76     }
77
78     function DataList(){
// Constructor function
79         $
this->DataHeight = 150;
80
81         $
this->AllowSelection = 1;
82         $
this->AllowDelete = 1;
83         $
this->AllowInsert = 1;
84         $
this->AllowUpdate = 1;
85         $
this->AllowFilters = 1;
86         $
this->AllowNavigation = 1;
87         $
this->AllowPrinting = 1;
88         $
this->HideTableView = 0;
89         $
this->QuickSearch = 0;
90         $
this->AllowCSV = 0;
91         $
this->CSVSeparator = ",";
92         $
this->HighlightColor = '#FFF0C2'; // default highlight color
93
94         $
this->RecordsPerPage = 10;
95         $
this->Template = '';
96         $
this->HTML = '';
97         $
this->filterers = array();
98     }
99
100     function showTV(){
101         
if($this->SeparateDV){
102             $
this->HideTableView = ($this->Permissions[2]==0 ? 1 : 0);
103         }
104     }
105
106     function hideTV(){
107         
if($this->SeparateDV){
108             $
this->HideTableView = 1;
109         }
110     }
111
112     function Render(){
113     
// get post and get variables
114         
global $Translation;
115
116         $adminConfig = config(
'adminConfig');
117
118         $FiltersPerGroup =
4;
119         $buttonWholeWidth =
136;
120
121         $current_view =
''; /* TV, DV, TVDV, TVP, DVP, Filters */
122
123         $Embedded = intval($_REQUEST[
'Embedded']);
124         $AutoClose = intval($_REQUEST[
'AutoClose']);
125
126         $SortField = $_REQUEST[
"SortField"];
127         $SortDirection = $_REQUEST[
"SortDirection"];
128         $FirstRecord = $_REQUEST[
"FirstRecord"];
129         $ScrollUp_y = $_REQUEST[
"ScrollUp_y"];
130         $ScrollDn_y = $_REQUEST[
"ScrollDn_y"];
131         $Previous_x = $_REQUEST[
"Previous_x"];
132         $Next_x = $_REQUEST[
"Next_x"];
133         $Filter_x = $_REQUEST[
"Filter_x"];
134         $SaveFilter_x = $_REQUEST[
"SaveFilter_x"];
135         $NoFilter_x = $_REQUEST[
"NoFilter_x"];
136         $CancelFilter = $_REQUEST[
"CancelFilter"];
137         $ApplyFilter = $_REQUEST[
"ApplyFilter"];
138         $Search_x = $_REQUEST[
"Search_x"];
139         $SearchString = (get_magic_quotes_gpc() ? stripslashes($_REQUEST[
'SearchString']) : $_REQUEST['SearchString']);
140         $CSV_x = $_REQUEST[
"CSV_x"];
141
142         $FilterAnd = $_REQUEST[
"FilterAnd"];
143         $FilterField = $_REQUEST[
"FilterField"];
144         $FilterOperator = $_REQUEST[
"FilterOperator"];
145         
if(is_array($_REQUEST['FilterValue'])){
146             
foreach($_REQUEST['FilterValue'] as $fvi=>$fv){
147                 $FilterValue[$fvi]=(get_magic_quotes_gpc() ? stripslashes($fv) : $fv);
148             }
149         }
150
151         $Print_x = $_REQUEST[
'Print_x'];
152         $PrintTV = $_REQUEST[
'PrintTV'];
153         $PrintDV = $_REQUEST[
'PrintDV'];
154         $SelectedID = (get_magic_quotes_gpc() ? stripslashes($_REQUEST[
'SelectedID']) : $_REQUEST['SelectedID']);
155         $insert_x = $_REQUEST[
'insert_x'];
156         $update_x = $_REQUEST[
'update_x'];
157         $delete_x = $_REQUEST[
'delete_x'];
158         $SkipChecks = $_REQUEST[
'confirmed'];
159         $deselect_x = $_REQUEST[
'deselect_x'];
160         $addNew_x = $_REQUEST[
'addNew_x'];
161         $dvprint_x = $_REQUEST[
'dvprint_x'];
162         $DisplayRecords = (in_array($_REQUEST[
'DisplayRecords'], array('user', 'group')) ? $_REQUEST['DisplayRecords'] : 'all');
163
164         $mi = getMemberInfo();
165
166     
// insure authenticity of user inputs:
167         
if(is_array($FilterAnd)){
168             
foreach($FilterAnd as $i => $f){
169                 
if($f && !preg_match('/^(and|or)$/i', trim($f))){
170                     $FilterAnd[$i] =
'and';
171                 }
172             }
173         }
174         
if(is_array($FilterField)){
175             
foreach($FilterField as $ffi => $ffn){
176                 $FilterField[$ffi] = intval($ffn);
177             }
178         }
179         
if(is_array($FilterOperator)){
180             
foreach($FilterOperator as $i => $f){
181                 
if($f && !in_array(trim($f), array_keys($GLOBALS['filter_operators']))){
182                     $FilterOperator[$i] =
'';
183                 }
184             }
185         }
186         
if(!preg_match('/^\s*[1-9][0-9]*\s*(asc|desc)?(\s*,\s*[1-9][0-9]*\s*(asc|desc)?)*$/i', $SortField)){
187             $SortField =
'';
188         }
189         
if(!preg_match('/^(asc|desc)$/i', $SortDirection)){
190             $SortDirection =
'';
191         }
192
193         
if(!$this->AllowDelete){
194             $delete_x =
'';
195         }
196         
if(!$this->AllowDeleteOfParents){
197             $SkipChecks =
'';
198         }
199         
if(!$this->AllowInsert){
200             $insert_x =
'';
201             $addNew_x =
'';
202         }
203         
if(!$this->AllowUpdate){
204             $update_x =
'';
205         }
206         
if(!$this->AllowFilters){
207             $Filter_x =
'';
208         }
209         
if(!$this->AllowPrinting){
210             $Print_x =
'';
211             $PrintTV =
'';
212         }
213         
if(!$this->QuickSearch){
214             $SearchString =
'';
215         }
216         
if(!$this->AllowCSV){
217             $CSV_x =
'';
218         }
219
220     
// enforce record selection if user has edit/delete permissions on the current table
221         $AllowPrintDV=
1;
222         $
this->Permissions=getTablePermissions($this->TableName);
223         
if($this->Permissions[3] || $this->Permissions[4]){ // current user can edit or delete?
224             $
this->AllowSelection = 1;
225         }elseif(!$
this->AllowSelection){
226             $SelectedID=
'';
227             $AllowPrintDV=
0;
228             $PrintDV=
'';
229         }
230
231         
if(!$this->AllowSelection || !$SelectedID){ $dvprint_x=''; }
232
233         $
this->QueryFieldsIndexed=reIndex($this->QueryFieldsFilters);
234
235     
// determine type of current view: TV, DV, TVDV, TVP, DVP or Filters?
236         
if($this->SeparateDV){
237             $current_view =
'TV';
238             
if($Print_x != '' || $PrintTV != '') $current_view = 'TVP';
239             elseif($dvprint_x !=
'' || $PrintDV != '') $current_view = 'DVP';
240             elseif($Filter_x !=
'') $current_view = 'Filters';
241             elseif(($SelectedID && !$deselect_x && !$delete_x) || $addNew_x !=
'') $current_view = 'DV';
242         }
else{
243             $current_view =
'TVDV';
244             
if($Print_x != '' || $PrintTV != '') $current_view = 'TVP';
245             elseif($dvprint_x !=
'' || $PrintDV != '') $current_view = 'DVP';
246             elseif($Filter_x !=
'') $current_view = 'Filters';
247         }
248
249         $
this->HTML .= '<div class="row"><div class="col-xs-11 col-md-12">';
250         $
this->HTML .= '<form ' . (datalist_image_uploads_exist ? 'enctype="multipart/form-data" ' : '') . 'method="post" name="myform" action="' . $this->ScriptFileName . '">';
251         
if($Embedded) $this->HTML .= '<input name="Embedded" value="1" type="hidden">';
252         
if($AutoClose) $this->HTML .= '<input name="AutoClose" value="1" type="hidden">';
253         $
this->HTML .= '<script>';
254         $
this->HTML .= 'function enterAction(){';
255         $
this->HTML .= ' if($j("input[name=SearchString]:focus").length){ $j("#Search").click(); }';
256         $
this->HTML .= ' return false;';
257         $
this->HTML .= '}';
258         $
this->HTML .= '</script>';
259         $
this->HTML .= '<input id="EnterAction" type="submit" style="position: absolute; left: 0px; top: -250px;" onclick="return enterAction();">';
260
261         $
this->ContentType='tableview'; // default content type
262
263         
if($PrintTV != ''){
264             $Print_x =
1;
265             $_REQUEST[
'Print_x'] = 1;
266         }
267
268     
// handle user commands ...
269         
if($deselect_x != ''){
270             $SelectedID =
'';
271             $
this->showTV();
272         }
273
274         elseif($insert_x !=
''){
275             $SelectedID = call_user_func($
this->TableName.'_insert');
276
277             
// redirect to a safe url to avoid refreshing and thus
278             
// insertion of duplicate records.
279             $url = $
this->RedirectAfterInsert;
280             $insert_status =
'record-added-ok=' . rand();
281             
if(!$SelectedID) $insert_status = 'record-added-error=' . rand();
282
283             
// compose filters and sorting
284             
foreach($this->filterers as $filterer => $caption){
285                 
if($_REQUEST['filterer_' . $filterer] != '') $filtersGET .= '&filterer_' . $filterer . '=' . urlencode($_REQUEST['filterer_' . $filterer]);
286             }
287             
for($i = 1; $i <= (20 * $FiltersPerGroup); $i++){ // Number of filters allowed
288                 
if($FilterField[$i] != '' && $FilterOperator[$i] != '' && ($FilterValue[$i] != '' || strpos($FilterOperator[$i], 'empty'))){
289                     $filtersGET .=
"&FilterAnd[{$i}]={$FilterAnd[$i]}&FilterField[{$i}]={$FilterField[$i]}&FilterOperator[{$i}]={$FilterOperator[$i]}&FilterValue[{$i}]=" . urlencode($FilterValue[$i]);
290                 }
291             }
292             
if($Embedded) $filtersGET .= '&Embedded=1&SelectedID=' . urlencode($SelectedID);
293             
if($AutoClose) $filtersGET .= '&AutoClose=1';
294             $filtersGET .=
"&SortField={$SortField}&SortDirection={$SortDirection}&FirstRecord={$FirstRecord}";
295             $filtersGET .=
"&DisplayRecords={$DisplayRecords}";
296             $filtersGET .=
'&SearchString=' . urlencode($SearchString);
297             $filtersGET = substr($filtersGET,
1); // remove initial &
298
299             
if($url){
300                 
/* if designer specified a redirect-after-insert url */
301                 $url .= (strpos($url,
'?') !== false ? '&' : '?') . $insert_status;
302                 $url .= (strpos($url, $
this->ScriptFileName) !== false ? "&{$filtersGET}" : '');
303                 $url = str_replace(
"#ID#", urlencode($SelectedID), $url);
304             }
else{
305                 
/* if no redirect-after-insert url, use default */
306                 $url =
"{$this->ScriptFileName}?{$insert_status}&{$filtersGET}";
307
308                 
/* if DV and TV in same page, select new record */
309                 
if(!$this->SeparateDV) $url .= '&SelectedID=' . urlencode($SelectedID);
310             }
311
312             @header(
'Location: ' . $url);
313             $
this->HTML .= "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;url=" . $url ."\">";
314
315             
return;
316         }
317
318         elseif($delete_x !=
''){
319             $delete_res = call_user_func($
this->TableName.'_delete', $SelectedID, $this->AllowDeleteOfParents, $SkipChecks);
320             
// handle ajax delete requests
321             
if(is_ajax()){
322                 die($delete_res ? $delete_res :
'OK');
323             }
324
325             
if($delete_res){
326                 
//$_REQUEST['record-deleted-error'] = 1;
327                 $
this->HTML .= showNotifications($delete_res, 'alert alert-danger', false);
328                 $
this->hideTV();
329                 $current_view = ($
this->SeparateDV ? 'DV' : 'TVDV');
330             }
else{
331                 $_REQUEST[
'record-deleted-ok'] = 1;
332                 $SelectedID =
'';
333                 $
this->showTV();
334
335                 
/* close window if embedded */
336                 
if($Embedded){
337                     $
this->HTML .= '<script>$j(function(){ setTimeout(function(){ window.parent.jQuery(".modal").modal("hide"); }, 2000); })</script>';
338                 }
339             }
340         }
341
342         elseif($update_x !=
''){
343             $updated = call_user_func($
this->TableName.'_update', $SelectedID);
344
345             $update_status =
'record-updated-ok=' . rand();
346             
if($updated === false) $update_status = 'record-updated-error=' . rand();
347
348             
// compose filters and sorting
349             
foreach($this->filterers as $filterer => $caption){
350                 
if($_REQUEST['filterer_' . $filterer] != '') $filtersGET .= '&filterer_' . $filterer . '=' . urlencode($_REQUEST['filterer_' . $filterer]);
351             }
352             
for($i = 1; $i <= (20 * $FiltersPerGroup); $i++){ // Number of filters allowed
353                 
if($FilterField[$i] != '' && $FilterOperator[$i] != '' && ($FilterValue[$i] != '' || strpos($FilterOperator[$i], 'empty'))){
354                     $filtersGET .=
"&FilterAnd[{$i}]={$FilterAnd[$i]}&FilterField[{$i}]={$FilterField[$i]}&FilterOperator[{$i}]={$FilterOperator[$i]}&FilterValue[{$i}]=" . urlencode($FilterValue[$i]);
355                 }
356             }
357             $filtersGET .=
"&SortField={$SortField}&SortDirection={$SortDirection}&FirstRecord={$FirstRecord}&Embedded={$Embedded}";
358             
if($AutoClose) $filtersGET .= '&AutoClose=1';
359             $filtersGET .=
"&DisplayRecords={$DisplayRecords}";
360             $filtersGET .=
'&SearchString=' . urlencode($SearchString);
361             $filtersGET = substr($filtersGET,
1); // remove initial &
362
363             $redirectUrl = $
this->ScriptFileName . '?SelectedID=' . urlencode($SelectedID) . '&' . $filtersGET . '&' . $update_status;
364             @header(
"Location: $redirectUrl");
365             $
this->HTML .= '<META HTTP-EQUIV="Refresh" CONTENT="0;url='.$redirectUrl.'">';
366             
return;
367         }
368
369         elseif($addNew_x !=
''){
370             $SelectedID=
'';
371             $
this->hideTV();
372         }
373
374         elseif($Print_x !=
''){
375             
// print code here ....
376             $
this->AllowNavigation = 0;
377             $
this->AllowSelection = 0;
378         }
379
380         elseif($SaveFilter_x !=
'' && $this->AllowSavingFilters){
381             $filter_link = $_SERVER[
'HTTP_REFERER'] . '?SortField=' . urlencode($SortField) . '&SortDirection=' . $SortDirection . '&';
382             
for($i = 1; $i <= (20 * $FiltersPerGroup); $i++){ // Number of filters allowed
383                 
if(($FilterField[$i] != '' || $i == 1) && $FilterOperator[$i] != '' && ($FilterValue[$i] != '' || strpos($FilterOperator[$i], 'empty'))){
384                     $filter_link .= urlencode(
"FilterAnd[$i]") . '=' . urlencode($FilterAnd[$i]) . '&';
385                     $filter_link .= urlencode(
"FilterField[$i]") . '=' . urlencode($FilterField[$i]) . '&';
386                     $filter_link .= urlencode(
"FilterOperator[$i]") . '=' . urlencode($FilterOperator[$i]) . '&';
387                     $filter_link .= urlencode(
"FilterValue[$i]") . '=' . urlencode($FilterValue[$i]) . '&';
388                 }elseif(($i % $FiltersPerGroup ==
1) && in_array($FilterAnd[$i], array('and', 'or'))){
389                     
/* always include the and/or at the beginning of each group */
390                     $filter_link .= urlencode(
"FilterAnd[$i]") . '=' . urlencode($FilterAnd[$i]) . '&';
391                 }
392             }
393             $filter_link = substr($filter_link,
0, -1); /* trim last '&' */
394
395             $
this->HTML .= '<div id="saved_filter_source_code" class="row"><div class="col-md-6 col-md-offset-3">';
396                 $
this->HTML .= '<div class="panel panel-info">';
397                     $
this->HTML .= '<div class="panel-heading"><h3 class="panel-title">' . $Translation["saved filters title"] . "</h3></div>";
398                     $
this->HTML .= '<div class="panel-body">';
399                         $
this->HTML .= $Translation["saved filters instructions"];
400                         $
this->HTML .= '<textarea rows="4" class="form-control vspacer-lg" style="width: 100%;" onfocus="$j(this).select();">' . "&lt;a href=\"{$filter_link}\"&gt;Saved filter link&lt;a&gt;" . '</textarea>';
401                         $
this->HTML .= "<div><a href=\"{$filter_link}\" title=\"" . html_attr($filter_link) . "\">{$Translation['permalink']}</a></div>";
402                         $
this->HTML .= '<button type="button" class="btn btn-default btn-block vspacer-lg" onclick="$j(\'#saved_filter_source_code\').remove();"><i class="glyphicon glyphicon-remove"></i> ' . $Translation['hide code'] . '</button>';
403                     $
this->HTML .= '</div>';
404                 $
this->HTML .= '</div>';
405             $
this->HTML .= '</div></div>';
406         }
407
408         elseif($Filter_x !=
''){
409             $orderBy = array();
410             
if($SortField){
411                 $sortFields = explode(
',', $SortField);
412                 $i=
0;
413                 
foreach($sortFields as $sf){
414                     $tob = preg_split(
'/\s+/', $sf, 2);
415                     $orderBy[] = array(trim($tob[
0]) => (strtolower(trim($tob[1]))=='desc' ? 'desc' : 'asc'));
416                     $i++;
417                 }
418                 $orderBy[$i-
1][$tob[0]] = (strtolower(trim($SortDirection))=='desc' ? 'desc' : 'asc');
419             }
420
421             $currDir=dirname(__FILE__).
'/hooks'; // path to hooks folder
422             $uff=
"{$currDir}/{$this->TableName}.filters.{$mi['username']}.php"; // user-specific filter file
423             $gff=
"{$currDir}/{$this->TableName}.filters.{$mi['group']}.php"; // group-specific filter file
424             $tff=
"{$currDir}/{$this->TableName}.filters.php"; // table-specific filter file
425
426             
/*
427                 
if no explicit filter file exists, look for filter files in the hooks folder in this order:
428                     
1. tablename.filters.username.php ($uff)
429                     
2. tablename.filters.groupname.php ($gff)
430                     
3. tablename.filters.php ($tff)
431             */

432             
if(!is_file($this->FilterPage)){
433                 $
this->FilterPage='defaultFilters.php';
434                 
if(is_file($uff)){
435                     $
this->FilterPage=$uff;
436                 }elseif(is_file($gff)){
437                     $
this->FilterPage=$gff;
438                 }elseif(is_file($tff)){
439                     $
this->FilterPage=$tff;
440                 }
441             }
442
443             
if($this->FilterPage!=''){
444                 ob_start();
445                 @include($
this->FilterPage);
446                 $
out=ob_get_contents();
447                 ob_end_clean();
448                 $
this->HTML .= $out;
449             }
450             
// hidden variables ....
451                 $
this->HTML .= '<input name="SortField" value="'.$SortField.'" type="hidden" />';
452                 $
this->HTML .= '<input name="SortDirection" type="hidden" value="'.$SortDirection.'" />';
453                 $
this->HTML .= '<input name="FirstRecord" type="hidden" value="1" />';
454
455                 $
this->ContentType='filters';
456             
return;
457         }
458
459         elseif($NoFilter_x !=
''){
460             
// clear all filters ...
461             
for($i = 1; $i <= (datalist_filters_count * $FiltersPerGroup); $i++){ // Number of filters allowed
462                 $FilterField[$i] =
'';
463                 $FilterOperator[$i] =
'';
464                 $FilterValue[$i] =
'';
465             }
466             $DisplayRecords =
'all';
467             $SearchString =
'';
468             $FirstRecord =
1;
469
470             
// clear filterers
471             
foreach($this->filterers as $filterer => $caption){
472                 $_REQUEST[
'filterer_' . $filterer] = '';
473             }
474         }
475
476         elseif($SelectedID){
477             $
this->hideTV();
478         }
479
480     
// apply lookup filterers to the query
481         
foreach($this->filterers as $filterer => $caption){
482             
if($_REQUEST['filterer_' . $filterer] != ''){
483                 
if($this->QueryWhere == '')
484                     $
this->QueryWhere = "where ";
485                 
else
486                     $
this->QueryWhere .= " and ";
487                 $
this->QueryWhere .= "`{$this->TableName}`.`$filterer`='" . makeSafe($_REQUEST['filterer_' . $filterer]) . "' ";
488                 
break; // currently, only one filterer can be applied at a time
489             }
490         }
491
492     
// apply quick search to the query
493         
if($SearchString != ''){
494             
if($Search_x!=''){ $FirstRecord=1; }
495
496             
if($this->QueryWhere=='')
497                 $
this->QueryWhere = "where ";
498             
else
499                 $
this->QueryWhere .= " and ";
500
501             
foreach($this->QueryFieldsQS as $fName => $fCaption){
502                 
if(strpos($fName, '<img')===False){
503                     $
this->QuerySearchableFields[$fName]=$fCaption;
504                 }
505             }
506
507             $
this->QueryWhere.='('.implode(" LIKE '%".makeSafe($SearchString)."%' or ", array_keys($this->QuerySearchableFields))." LIKE '%".makeSafe($SearchString)."%')";
508         }
509
510
511     
// set query filters
512         $QueryHasWhere =
0;
513         
if(strpos($this->QueryWhere, 'where ')!==FALSE)
514             $QueryHasWhere =
1;
515
516         $WhereNeedsClosing =
0;
517         
for($i = 1; $i <= (datalist_filters_count * $FiltersPerGroup); $i+=$FiltersPerGroup){ // Number of filters allowed
518             
// test current filter group
519             $GroupHasFilters =
0;
520             
for($j = 0; $j < $FiltersPerGroup; $j++){
521                 
if($FilterField[$i+$j] != '' && $this->QueryFieldsIndexed[($FilterField[$i+$j])] != '' && $FilterOperator[$i+$j] != '' && ($FilterValue[$i+$j] != '' || strpos($FilterOperator[$i+$j], 'empty'))){
522                     $GroupHasFilters =
1;
523                     
break;
524                 }
525             }
526
527             
if($GroupHasFilters){
528                 
if(!stristr($this->QueryWhere, "where "))
529                     $
this->QueryWhere = "where (";
530                 elseif($QueryHasWhere){
531                     $
this->QueryWhere .= " and (";
532                     $QueryHasWhere =
0;
533                 }
534
535                 $
this->QueryWhere .= " <FilterGroup> " . $FilterAnd[$i] . " (";
536
537                 
for($j = 0; $j < $FiltersPerGroup; $j++){
538                     
if($FilterField[$i+$j] != '' && $this->QueryFieldsIndexed[($FilterField[$i+$j])] != '' && $FilterOperator[$i+$j] != '' && ($FilterValue[$i+$j] != '' || strpos($FilterOperator[$i+$j], 'empty'))){
539                         
if($FilterAnd[$i+$j]==''){
540                             $FilterAnd[$i+$j]=
'and';
541                         }
542                         
// test for date/time fields
543                         $tries=
0; $isDateTime=FALSE; $isDate=FALSE;
544                         $fieldName=str_replace(
'`', '', $this->QueryFieldsIndexed[($FilterField[$i+$j])]);
545                         list($tn, $fn)=explode(
'.', $fieldName);
546                         
while(!($res=sql("show columns from `$tn` like '$fn'", $eo)) && $tries<2){
547                             $tn=substr($tn,
0, -1);
548                             $tries++;
549                         }
550                         
if($row = @db_fetch_array($res)){
551                             
if($row['Type']=='date' || $row['Type']=='time'){
552                                 $isDateTime=TRUE;
553                                 
if($row['Type']=='date'){
554                                     $isDate=True;
555                                 }
556                             }
557                         }
558                         
// end of test
559                         
if($FilterOperator[$i+$j]=='is-empty' && !$isDateTime){
560                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " (" . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . "='' or " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " is NULL) </FilterItem>";
561                         }elseif($FilterOperator[$i+$j]==
'is-not-empty' && !$isDateTime){
562                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . "!='' </FilterItem>";
563                         }elseif($FilterOperator[$i+$j]==
'is-empty' && $isDateTime){
564                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " (" . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . "=0 or " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " is NULL) </FilterItem>";
565                         }elseif($FilterOperator[$i+$j]==
'is-not-empty' && $isDateTime){
566                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . "!=0 </FilterItem>";
567                         }elseif($FilterOperator[$i+$j]==
'like' && !strstr($FilterValue[$i+$j], "%") && !strstr($FilterValue[$i+$j], "_")){
568                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " like '%" . makeSafe($FilterValue[$i+$j]) . "%' </FilterItem>";
569                         }elseif($FilterOperator[$i+$j]==
'not-like' && !strstr($FilterValue[$i+$j], "%") && !strstr($FilterValue[$i+$j], "_")){
570                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " not like '%" . makeSafe($FilterValue[$i+$j]) . "%' </FilterItem>";
571                         }elseif($isDate){
572                             $dateValue = toMySQLDate($FilterValue[$i+$j]);
573                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " " . $GLOBALS['filter_operators'][$FilterOperator[$i+$j]] . " '$dateValue' </FilterItem>";
574                         }
else{
575                             $
this->QueryWhere .= " <FilterItem> " . $FilterAnd[$i+$j] . " " . $this->QueryFieldsIndexed[($FilterField[$i+$j])] . " " . $GLOBALS['filter_operators'][$FilterOperator[$i+$j]] . " '" . makeSafe($FilterValue[$i+$j]) . "' </FilterItem>";
576                         }
577                     }
578                 }
579
580                 $
this->QueryWhere .= ") </FilterGroup>";
581                 $WhereNeedsClosing =
1;
582             }
583         }
584
585         
if($WhereNeedsClosing)
586             $
this->QueryWhere .= ")";
587
588     
// set query sort
589         
if(!stristr($this->QueryOrder, "order by ") && $SortField != '' && $this->AllowSorting){
590             $actualSortField = $SortField;
591             
foreach($this->SortFields as $fieldNum => $fieldSort){
592                 $actualSortField = str_replace(
" $fieldNum ", " $fieldSort ", " $actualSortField ");
593                 $actualSortField = str_replace(
",$fieldNum ", ",$fieldSort ", " $actualSortField ");
594             }
595             $
this->QueryOrder = "order by $actualSortField $SortDirection";
596         }
597
598     
// clean up query
599         $
this->QueryWhere = str_replace('( <FilterGroup> and ', '( ', $this->QueryWhere);
600         $
this->QueryWhere = str_replace('( <FilterGroup> or ', '( ', $this->QueryWhere);
601         $
this->QueryWhere = str_replace('( <FilterItem> and ', '( ', $this->QueryWhere);
602         $
this->QueryWhere = str_replace('( <FilterItem> or ', '( ', $this->QueryWhere);
603         $
this->QueryWhere = str_replace('<FilterGroup>', '', $this->QueryWhere);
604         $
this->QueryWhere = str_replace('</FilterGroup>', '', $this->QueryWhere);
605         $
this->QueryWhere = str_replace('<FilterItem>', '', $this->QueryWhere);
606         $
this->QueryWhere = str_replace('</FilterItem>', '', $this->QueryWhere);
607
608     
// if no 'order by' clause found, apply default sorting if specified
609         
if($this->DefaultSortField != '' && $this->QueryOrder == ''){
610             $
this->QueryOrder="order by ".$this->DefaultSortField." ".$this->DefaultSortDirection;
611         }
612
613     
// get count of matching records ...
614         $TempQuery =
'SELECT count(1) from '.$this->QueryFrom.' '.$this->QueryWhere;
615         $RecordCount = sqlValue($TempQuery);
616         $FieldCountTV = count($
this->QueryFieldsTV);
617         $FieldCountCSV = count($
this->QueryFieldsCSV);
618         $FieldCountFilters = count($
this->QueryFieldsFilters);
619         
if(!$RecordCount){
620             $FirstRecord=
1;
621         }
622
623     
// Output CSV on request
624         
if($CSV_x != ''){
625             $
this->HTML = '';
626             
if(datalist_db_encoding == 'UTF-8') $this->HTML = "\xEF\xBB\xBF"; // BOM characters for UTF-8 output
627
628         
// execute query for CSV output
629             $fieldList=
'';
630             
foreach($this->QueryFieldsCSV as $fn=>$fc)
631                 $fieldList.=
"$fn as `$fc`, ";
632             $fieldList=substr($fieldList,
0, -2);
633             $csvQuery =
'SELECT '.$fieldList.' from '.$this->QueryFrom.' '.$this->QueryWhere.' '.$this->QueryOrder;
634
635             
// hook: table_csv
636             
if(function_exists($this->TableName.'_csv')){
637                 $args = array();
638                 $mq = call_user_func_array($
this->TableName . '_csv', array($csvQuery, $mi, &$args));
639                 $csvQuery = ($mq ? $mq : $csvQuery);
640             }
641
642             $result = sql($csvQuery, $eo);
643
644         
// output CSV field names
645             
for($i = 0; $i < $FieldCountCSV; $i++)
646                 $
this->HTML .= "\"" . db_field_name($result, $i) . "\"" . $this->CSVSeparator;
647             $
this->HTML .= "\n\n";
648
649         
// output CSV data
650             
while($row = db_fetch_row($result)){
651                 
for($i = 0; $i < $FieldCountCSV; $i++)
652                     $
this->HTML .= "\"" . str_replace(array("\r\n", "\r", "\n", '"'), array(' ', ' ', ' ', '""'), strip_tags($row[$i])) . "\"" . $this->CSVSeparator;
653                 $
this->HTML .= "\n\n";
654             }
655             $
this->HTML = str_replace($this->CSVSeparator . "\n\n", "\n", $this->HTML);
656             $
this->HTML = substr($this->HTML, 0, - 1);
657
658         
// clean any output buffers
659             
while(@ob_end_clean());
660
661         
// output CSV HTTP headers ...
662             header(
'HTTP/1.1 200 OK');
663             header(
'Date: ' . @date("D M j G:i:s T Y"));
664             header(
'Last-Modified: ' . @date("D M j G:i:s T Y"));
665             header(
"Content-Type: application/force-download");
666             header(
"Content-Length: " . (string)(strlen($this->HTML)));
667             header(
"Content-Transfer-Encoding: Binary");
668             header(
"Content-Disposition: attachment; filename=$this->TableName.csv");
669
670         
// send output and quit script
671             echo $
this->HTML;
672             exit;
673         }
674         $t = time();
// just a random number for any purpose ...
675
676     
// should SelectedID be reset on clicking TV buttons?
677         $resetSelection = ($
this->SeparateDV ? "document.myform.SelectedID.value = '';" : "document.myform.writeAttribute('novalidate', 'novalidate');");
678
679         
if($current_view == 'DV' && !$Embedded){
680             $
this->HTML .= '<div class="page-header">';
681                 $
this->HTML .= '<h1>';
682                     $
this->HTML .= '<a style="text-decoration: none; color: inherit;" href="' . $this->TableName . '_view.php"><img src="' . $this->TableIcon . '"> ' . $this->TableTitle . '</a>';
683                     
/* show add new button if user can insert and there is a selected record */
684                     
if($SelectedID && $this->Permissions[1] && $this->SeparateDV && $this->AllowInsert){
685                         $
this->HTML .= ' <button type="submit" id="addNew" name="addNew_x" value="1" class="btn btn-success"><i class="glyphicon glyphicon-plus-sign"></i> ' . $Translation['Add New'] . '</button>';
686                     }
687                 $
this->HTML .= '</h1>';
688             $
this->HTML .= '</div>';
689         }
690
691     
// quick search and TV action buttons
692         
if(!$this->HideTableView && !($dvprint_x && $this->AllowSelection && $SelectedID) && !$PrintDV){
693             $buttons_all = $quick_search_html =
'';
694
695             
if($Print_x == ''){
696
697                 
// display 'Add New' icon
698                 
if($this->Permissions[1] && $this->SeparateDV && $this->AllowInsert){
699                     $buttons_all .=
'<button type="submit" id="addNew" name="addNew_x" value="1" class="btn btn-success"><i class="glyphicon glyphicon-plus-sign"></i> ' . $Translation['Add New'] . '</button>';
700                     $buttonsCount++;
701                 }
702
703                 
// display Print icon
704                 
if($this->AllowPrinting){
705                     $buttons_all .=
'<button onClick="document.myform.NoDV.value=1; ' . $resetSelection . ' return true;" type="submit" name="Print_x" id="Print" value="1" class="btn btn-default"><i class="glyphicon glyphicon-print"></i> ' . $Translation['Print Preview'] . '</button>';
706                     $buttonsCount++;
707                 }
708
709                 
// display CSV icon
710                 
if($this->AllowCSV){
711                     $buttons_all .=
'<button onClick="document.myform.NoDV.value=1; ' . $resetSelection . ' return true;" type="submit" name="CSV_x" id="CSV" value="1" class="btn btn-default"><i class="glyphicon glyphicon-download-alt"></i> ' . $Translation['CSV'] . '</button>';
712                     $buttonsCount++;
713                 }
714
715                 
// display Filter icon
716                 
if($this->AllowFilters){
717                     $buttons_all .=
'<button onClick="document.myform.NoDV.value=1; ' . $resetSelection . ' return true;" type="submit" name="Filter_x" id="Filter" value="1" class="btn btn-default"><i class="glyphicon glyphicon-filter"></i> ' . $Translation['filter'] . '</button>';
718                     $buttonsCount++;
719                 }
720
721                 
// display Show All icon
722                 
if(($this->AllowFilters)){
723                     $buttons_all .=
'<button onClick="document.myform.NoDV.value=1; ' . $resetSelection . ' return true;" type="submit" name="NoFilter_x" id="NoFilter" value="1" class="btn btn-default"><i class="glyphicon glyphicon-remove-circle"></i> ' . $Translation['Reset Filters'] . '</button>';
724                     $buttonsCount++;
725                 }
726
727                 $quick_search_html .=
'<div class="input-group" id="quick-search">';
728                     $quick_search_html .=
'<input type="text" name="SearchString" value="' . html_attr($SearchString) . '" class="form-control" placeholder="' . html_attr($this->QuickSearchText) . '">';
729                     $quick_search_html .=
'<span class="input-group-btn">';
730                         $quick_search_html .=
'<button name="Search_x" value="1" id="Search" type="submit" onClick="' . $resetSelection . ' document.myform.NoDV.value=1; return true;" class="btn btn-default" title="' . html_attr($this->QuickSearchText) . '"><i class="glyphicon glyphicon-search"></i></button>';
731                         $quick_search_html .=
'<button name="NoFilter_x" value="1" id="NoFilter_x" type="submit" onClick="' . $resetSelection . ' document.myform.NoDV.value=1; return true;" class="btn btn-default" title="' . html_attr($Translation['Reset Filters']) . '"><i class="glyphicon glyphicon-remove-circle"></i></button>';
732                     $quick_search_html .=
'</span>';
733                 $quick_search_html .=
'</div>';
734             }
else{
735                 $buttons_all .=
'<button class="btn btn-primary" type="button" id="sendToPrinter" onClick="window.print();"><i class="glyphicon glyphicon-print"></i> ' . $Translation['Print'] . '</button>';
736                 $buttons_all .=
'<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-remove-circle"></i> ' . $Translation['Cancel Printing'] . '</button>';
737             }
738
739             
/* if user can print DV, add action to 'More' menu */
740             $selected_records_more = array();
741
742             
if($AllowPrintDV){
743                 $selected_records_more[] = array(
744                     
'function' => ($this->SeparateDV ? 'print_multiple_dv_sdv' : 'print_multiple_dv_tvdv'),
745                     
'title' => $Translation['Print Preview Detail View'],
746                     
'icon' => 'print'
747                 );
748             }
749
750             
/* if user can mass-delete selected records, add action to 'More' menu */
751             
if($this->AllowMassDelete && $this->AllowDelete){
752                 $selected_records_more[] = array(
753                     
'function' => 'mass_delete',
754                     
'title' => $Translation['Delete'],
755                     
'icon' => 'trash',
756                     
'class' => 'text-danger'
757                 );
758             }
759
760             
/* if user is admin, add 'Change owner' action to 'More' menu */
761             
/* also, add help link for adding more actions */
762             
if($mi['admin']){
763                 $selected_records_more[] = array(
764                     
'function' => 'mass_change_owner',
765                     
'title' => $Translation['Change owner'],
766                     
'icon' => 'user'
767                 );
768                 $selected_records_more[] = array(
769                     
'function' => 'add_more_actions_link',
770                     
'title' => $Translation['Add more actions'],
771                     
'icon' => 'question-sign',
772                     
'class' => 'text-info'
773                 );
774             }
775
776             
/* user-defined actions ... should be set in the {tablename}_batch_actions() function in hooks/{tablename}.php */
777             $user_actions = array();
778             
if(function_exists($this->TableName.'_batch_actions')){
779                 $args = array();
780                 $user_actions = call_user_func_array($
this->TableName . '_batch_actions', array(&$args));
781                 
if(is_array($user_actions) && count($user_actions)){
782                     $selected_records_more = array_merge($selected_records_more, $user_actions);
783                 }
784             }
785
786             $actual_more_count =
0;
787             $more_menu = $more_menu_js =
'';
788             
if(count($selected_records_more)){
789                 $more_menu .=
'<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" id="selected_records_more"><i class="glyphicon glyphicon-check"></i> ' . $Translation['More'] . ' <span class="caret"></span></button>';
790                 $more_menu .=
'<ul class="dropdown-menu" role="menu">';
791                 
foreach($selected_records_more as $action){
792                     
if(!$action['function'] || !$action['title']) continue;
793                     $action[
'class'] = (!isset($action['class']) ? '' : $action['class']);
794                     $action[
'icon'] = (!isset($action['icon']) ? '' : $action['icon']);
795                     $actual_more_count++;
796                     $more_menu .=
'<li>' .
797                             
'<a href="#" id="selected_records_' . $action['function'] . '">' .
798                                 
'<span class="' . $action['class'] . '">' .
799                                     ($action[
'icon'] ? '<i class="glyphicon glyphicon-' . $action['icon'] . '"></i> ' : '') .
800                                     $action[
'title'] .
801                                 
'</span>' .
802                             
'</a>' .
803                         
'</li>';
804
805                     
// on clicking an action, call its js handler function, passing the current table name and an array of selected IDs to it
806                     $more_menu_js .=
"jQuery('[id=selected_records_{$action['function']}]').click(function(){ {$action['function']}('{$this->TableName}', get_selected_records_ids()); return false; });";
807                 }
808                 $more_menu .=
'</ul>';
809             }
810
811             
if($Embedded){
812                 $
this->HTML .= '<script>$j(function(){ $j(\'[id^=notification-]\').parent().css({\'margin-top\': \'15px\', \'margin-bottom\': \'0\'}); })</script>';
813             }
else{
814                 $
this->HTML .= '<div class="page-header">';
815                     $
this->HTML .= '<h1>';
816                         $
this->HTML .= '<div class="row">';
817                             $
this->HTML .= '<div class="col-sm-8">';
818                                 $
this->HTML .= '<a style="text-decoration: none; color: inherit;" href="' . $this->TableName . '_view.php"><img src="' . $this->TableIcon . '"> ' . $this->TableTitle . '</a>';
819                             $
this->HTML .= '</div>';
820                             
if($this->QuickSearch){
821                                 $
this->HTML .= '<div class="col-sm-4">';
822                                     $
this->HTML .= $quick_search_html;
823                                 $
this->HTML .= '</div>';
824                             }
825                         $
this->HTML .= '</div>';
826                     $
this->HTML .= '</h1>';
827                 $
this->HTML .= '</div>';
828
829                 $
this->HTML .= '<div id="top_buttons" class="hidden-print">';
830                     
/* .all_records: container for buttons that don't need a selection */
831                     
/* .selected_records: container for buttons that need a selection */
832                     $
this->HTML .= '<div class="btn-group btn-group-lg visible-md visible-lg all_records pull-left">' . $buttons_all . '</div>';
833                     $
this->HTML .= '<div class="btn-group btn-group-lg visible-md visible-lg selected_records hidden pull-left hspacer-lg">' . $buttons_selected . ($actual_more_count ? $more_menu : '') . '</div>';
834                     $
this->HTML .= '<div class="btn-group-vertical btn-group-lg visible-xs visible-sm all_records">' . $buttons_all . '</div>';
835                     $
this->HTML .= '<div class="btn-group-vertical btn-group-lg visible-xs visible-sm selected_records hidden vspacer-lg">' . $buttons_selected . ($actual_more_count ? $more_menu : '') . '</div>';
836                     $
this->HTML .= '<div class="clearfix"></div><p></p>';
837                 $
this->HTML .= '</div>';
838
839                 $
this->HTML .= '<div class="row"><div class="table_view col-xs-12 ' . $this->TVClasses . '">';
840             }
841
842             
if($Print_x != ''){
843                 
/* fix top margin for print-preview */
844                 $
this->HTML .= '<style>body{ padding-top: 0 !important; }</style>';
845
846                 
/* disable links inside table body to prevent printing their href */
847                 $
this->HTML .= '<script>jQuery(function(){ jQuery("tbody a").removeAttr("href").removeAttr("rel"); });</script>';
848             }
849
850             
// script for focusing into the search box on loading the page
851             
// and for declaring record action handlers
852             $
this->HTML .= '<script>jQuery(function(){ jQuery("input[name=SearchString]").focus(); ' . $more_menu_js . ' });</script>';
853
854         }
855
856     
// begin table and display table title
857         
if(!$this->HideTableView && !($dvprint_x && $this->AllowSelection && $SelectedID) && !$PrintDV && !$Embedded){
858             $
this->HTML .= '<div class="table-responsive"><table class="table table-striped table-bordered table-hover">';
859
860             $
this->HTML .= '<thead><tr>';
861             
if(!$Print_x) $this->HTML .= '<th style="width: 18px;" class="text-center"><input class="hidden-print" type="checkbox" title="' . html_attr($Translation['Select all records']) . '" id="select_all_records"></th>';
862         
// Templates
863             $rowTemplate = $selrowTemplate =
'';
864             
if($this->Template){
865                 $rowTemplate = @file_get_contents(
'./' . $this->Template);
866                 
if($rowTemplate && $this->SelectedTemplate){
867                     $selrowTemplate = @file_get_contents(
'./' . $this->SelectedTemplate);
868                 }
869             }
870
871             
// process translations
872             
if($rowTemplate){
873                 
foreach($Translation as $symbol=>$trans){
874                     $rowTemplate=str_replace(
"<%%TRANSLATION($symbol)%%>", $trans, $rowTemplate);
875                 }
876             }
877             
if($selrowTemplate){
878                 
foreach($Translation as $symbol=>$trans){
879                     $selrowTemplate=str_replace(
"<%%TRANSLATION($symbol)%%>", $trans, $selrowTemplate);
880                 }
881             }
882         
// End of templates
883
884         
// $this->ccffv: map $FilterField values to field captions as stored in ColCaption
885             $
this->ccffv = array();
886             
foreach($this->ColCaption as $captionIndex => $caption){
887                 $ffv =
1;
888                 
foreach($this->QueryFieldsFilters as $uselessKey => $filterCaption){
889                     
if($caption == $filterCaption){
890                         $
this->ccffv[$captionIndex] = $ffv;
891                     }
892                     $ffv++;
893                 }
894             }
895
896         
// display table headers
897             $forceHeaderWidth =
false;
898             
if($rowTemplate=='' || $this->ShowTableHeader){
899                 
for($i = 0; $i < count($this->ColCaption); $i++){
900                     
/* Sorting icon and link */
901                     $sort1 = $sort2 = $filterHint =
'';
902                     
if($this->AllowSorting == 1){
903                         
if($current_view != 'TVP'){
904                             $sort1 =
"<a href=\"{$this->ScriptFileName}?SortDirection=asc&SortField=".($this->ColNumber[$i])."\" onClick=\"$resetSelection document.myform.NoDV.value=1; document.myform.SortDirection.value='asc'; document.myform.SortField.value = '".($this->ColNumber[$i])."'; document.myform.submit(); return false;\" class=\"TableHeader\">";
905                             $sort2 =
"</a>";
906                         }
907                         
if($this->ColNumber[$i] == $SortField){
908                             $SortDirection = ($SortDirection ==
"asc" ? "desc" : "asc");
909                             
if($current_view != 'TVP')
910                                 $sort1 =
"<a href=\"{$this->ScriptFileName}?SortDirection=$SortDirection&SortField=".($this->ColNumber[$i])."\" onClick=\"$resetSelection document.myform.NoDV.value=1; document.myform.SortDirection.value='$SortDirection'; document.myform.SortField.value = ".($this->ColNumber[$i])."; document.myform.submit(); return false;\" class=\"TableHeader\">";
911                             $sort2 =
" <i class=\"text-warning glyphicon glyphicon-sort-by-attributes" . ($SortDirection == 'desc' ? '' : '-alt') . "\"></i>{$sort2}";
912                             $SortDirection = ($SortDirection ==
"asc" ? "desc" : "asc");
913                         }
914                     }
915
916                     
/* Filtering icon and hint */
917                     
if($this->AllowFilters && is_array($FilterField)){
918                         
// check to see if there is any filter applied on the current field
919                         
if(isset($this->ccffv[$i]) && in_array($this->ccffv[$i], $FilterField)){
920                             
// render filter icon
921                             $filterHint =
'&nbsp;<button type="submit" class="btn btn-default btn-xs' . ($current_view == 'TVP' ? ' disabled' : '') . '" name="Filter_x" value="1" title="'.html_attr($Translation['filtered field']).'"><i class="glyphicon glyphicon-filter"></i></button>';
922                         }
923                     }
924
925                     $
this->HTML .= "\t<th class=\"{$this->TableName}-{$this->ColFieldName[$i]}\" " . ($forceHeaderWidth ? ' style="width: ' . ($this->ColWidth[$i] ? $this->ColWidth[$i] : 100) . 'px;"' : '') . ">{$sort1}{$this->ColCaption[$i]}{$sort2}{$filterHint}</th>\n";
926                 }
927             }elseif($current_view !=
'TVP'){
928                 
// Display a Sort by drop down
929                 $
this->HTML .= "\t<th class=\"hidden-print\" colspan=\"" . (count($this->ColCaption)) . "\">";
930                 $
this->HTML .= "\t<div class=\"pull-right\" id=\"order-by-selector\">";
931
932                 
if($this->AllowSorting == 1){
933                     $sortCombo =
new Combo;
934                     
for($i=0; $i < count($this->ColCaption); $i++){
935                         $sortCombo->ListItem[] = $
this->ColCaption[$i];
936                         $sortCombo->ListData[] = $
this->ColNumber[$i];
937                     }
938                     $sortCombo->SelectName =
"FieldsList";
939                     $sortCombo->SelectedData = $SortField;
940                     $sortCombo->Class =
'';
941                     $sortCombo->SelectedClass =
'';
942                     $sortCombo->Render();
943                     $sortby_dropdown = $sortCombo->HTML;
944                     $sortby_dropdown = str_replace(
'<select ', "<select onChange=\"document.myform.SortDirection.value='$SortDirection'; document.myform.SortField.value=document.myform.FieldsList.value; document.myform.NoDV.value=1; document.myform.submit();\" ", $sortby_dropdown);
945                     
if($SortField){
946                         $SortDirection = ($SortDirection ==
'desc' ? 'asc' : 'desc');
947                         $sort_class = ($SortDirection ==
'asc' ? 'sort-by-attributes-alt' : 'sort-by-attributes');
948                         $sort =
"<a href=\"javascript: document.myform.NoDV.value=1; document.myform.SortDirection.value='{$SortDirection}'; document.myform.SortField.value='{$SortField}'; document.myform.submit();\" class=TableHeader><i class=\"text-warning glyphicon glyphicon-{$sort_class}\"></i></a>";
949                         $SortDirection = ($SortDirection ==
'desc' ? 'asc' : 'desc');
950                     }
else{
951                         $sort =
'';
952                     }
953
954                     $sortby_sep =
'<span class="hspacer-md"></span>';
955
956                     $
this->HTML .= "{$Translation['order by']}{$sortby_sep}{$sortby_dropdown}{$sortby_sep}{$sort}{$sortby_sep}";
957                 }
958                 $
this->HTML .= "</div><style>#s2id_FieldsList{ min-width: 12em; width: unset !important; }</style></th>\n";
959             }
960
961         
// table view navigation code ...
962             
if($RecordCount && $this->AllowNavigation && $RecordCount>$this->RecordsPerPage){
963                 
while($FirstRecord > $RecordCount)
964                     $FirstRecord -= $
this->RecordsPerPage;
965
966                 
if($FirstRecord == '' || $FirstRecord < 1) $FirstRecord = 1;
967
968                 
if($Previous_x != ''){
969                     $FirstRecord -= $
this->RecordsPerPage;
970                     
if($FirstRecord <= 0)
971                         $FirstRecord =
1;
972                 }elseif($Next_x !=
''){
973                     $FirstRecord += $
this->RecordsPerPage;
974                     
if($FirstRecord > $RecordCount)
975                         $FirstRecord = $RecordCount - ($RecordCount % $
this->RecordsPerPage) + 1;
976                     
if($FirstRecord > $RecordCount)
977                         $FirstRecord = $RecordCount - $
this->RecordsPerPage + 1;
978                     
if($FirstRecord <= 0)
979                         $FirstRecord =
1;
980                 }
981
982             }elseif($RecordCount){
983                 $FirstRecord =
1;
984                 $
this->RecordsPerPage = 2000; // a limit on max records in print preview to avoid performance drops
985             }
986         
// end of table view navigation code
987             $
this->HTML .= "\n\t</tr>\n\n</thead>\n\n<tbody><!-- tv data below -->\n";
988
989             $i =
0;
990             $hc=
new CI_Input();
991             $hc->charset = datalist_db_encoding;
992             
if($RecordCount){
993                 $i = $FirstRecord;
994             
// execute query for table view
995                 $query_fields = array();
996                 
foreach($this->QueryFieldsTV as $fn => $fc)
997                     $query_fields[] =
"$fn as `$fc`";
998                 $fieldList = implode(
', ', $query_fields);
999
1000                 
if($this->PrimaryKey)
1001                     $fieldList .=
", $this->PrimaryKey as '" . str_replace('`', '', $this->PrimaryKey) . "'";
1002
1003                 $tvQuery =
"SELECT {$fieldList} from {$this->QueryFrom} {$this->QueryWhere} {$this->QueryOrder}";
1004                 $result = sql($tvQuery .
" limit " . ($i-1) . ",{$this->RecordsPerPage}", $eo);
1005                 
while(($row = db_fetch_array($result)) && ($i < ($FirstRecord + $this->RecordsPerPage))){
1006                     
/* skip displaying the current record if we're in TVP or multiple DVP and the record is not checked */
1007                     
if(($PrintTV || $Print_x) && count($_REQUEST['record_selector']) && !in_array($row[$FieldCountTV], $_REQUEST['record_selector'])) continue;
1008
1009                     $attr_id = html_attr($row[$FieldCountTV]);
/* pk value suitable for inserting into html tag attributes */
1010                     $js_id = addslashes($row[$FieldCountTV]);
/* pk value suitable for inserting into js strings */
1011
1012                     
/* show record selector except in TVP */
1013                     
if($Print_x != ''){ $this->HTML .= '<tr>'; }
1014
1015                     
if(!$Print_x){
1016                         $
this->HTML .= ($SelectedID == $row[$FieldCountTV] ? '<tr class="active">' : '<tr>');
1017                         $
checked = (is_array($_REQUEST['record_selector']) && in_array($row[$FieldCountTV], $_REQUEST['record_selector']) ? ' checked' : '');
1018                         $
this->HTML .= "<td class=\"text-center\"><input class=\"hidden-print record_selector\" type=\"checkbox\" id=\"record_selector_{$attr_id}\" name=\"record_selector[]\" value=\"{$attr_id}\"{$checked}></td>";
1019                     }
1020
1021                     
/* apply record templates */
1022                     
if($rowTemplate != ''){
1023                         $rowTemp = $rowTemplate;
1024                         
if($this->AllowSelection == 1 && $SelectedID == $row[$FieldCountTV] && $selrowTemplate != ''){
1025                             $rowTemp = $selrowTemplate;
1026                         }
1027
1028                         
if($this->AllowSelection == 1 && $SelectedID != $row[$FieldCountTV]){
1029                             $rowTemp = str_replace(
'<%%SELECT%%>',"<a onclick=\"document.myform.SelectedField.value=this.parentNode.cellIndex; document.myform.SelectedID.value='" . addslashes($row[$FieldCountTV]) . "'; document.myform.submit(); return false;\" href=\"{$this->ScriptFileName}?SelectedID=" . html_attr($row[$FieldCountTV]) . "\" style=\"display: block; padding:0px;\">",$rowTemp);
1030                             $rowTemp = str_replace(
'<%%ENDSELECT%%>','</a>',$rowTemp);
1031                         }
else{
1032                             $rowTemp = str_replace(
'<%%SELECT%%>', '', $rowTemp);
1033                             $rowTemp = str_replace(
'<%%ENDSELECT%%>', '', $rowTemp);
1034                         }
1035
1036                         
for($j = 0; $j < $FieldCountTV; $j++){
1037                             $fieldTVCaption = current(array_slice($
this->QueryFieldsTV, $j, 1));
1038
1039                             $fd = $row[$j];
1040                             
/* apply nl2br only for non-HTML data */
1041                             
if($row[$j] == strip_tags($row[$j])){
1042                                 $fd = nl2br($row[$j]);
1043                             }
1044
1045                             
/* Sanitize output against XSS attacks */
1046                             $fd = $hc->xss_clean($fd);
1047
1048                             
/*
1049                                 the TV template could contain field placeholders
in the format
1050                                 <%%FIELD_n%%> or <%%VALUE(Field caption)%%> or <%%HTML_ATTR(field caption)%%>
1051                             */

1052                             $rowTemp = str_replace(
"<%%FIELD_$j%%>", thisOr($fd, ''), $rowTemp);
1053                             $rowTemp = str_replace(
"<%%VALUE($fieldTVCaption)%%>", thisOr($fd, ''), $rowTemp);
1054                             $rowTemp = str_replace(
"<%%HTML_ATTR($fieldTVCaption)%%>", html_attr($fd), $rowTemp);
1055
1056                             
if(strpos($rowTemp, "<%%YOUTUBETHUMB($fieldTVCaption)%%>") !== false) $rowTemp = str_replace("<%%YOUTUBETHUMB($fieldTVCaption)%%>", thisOr(get_embed('youtube', $fd, '', '', 'thumbnail_url'), 'blank.gif'), $rowTemp);
1057                             
if(strpos($rowTemp, "<%%GOOGLEMAPTHUMB($fieldTVCaption)%%>") !== false) $rowTemp = str_replace("<%%GOOGLEMAPTHUMB($fieldTVCaption)%%>", thisOr(get_embed('googlemap', $fd, '', '', 'thumbnail_url'), 'blank.gif'), $rowTemp);
1058                             
if(thisOr($fd)=='&nbsp;' && preg_match('/<a href=".*?&nbsp;.*?<\/a>/i', $rowTemp, $m)){
1059                                 $rowTemp=str_replace($m[
0], '', $rowTemp);
1060                             }
1061                         }
1062
1063                         $
this->HTML .= $rowTemp;
1064                         $rowTemp =
'';
1065
1066                     }
else{
1067                         
// default view if no template
1068                         
for($j = 0; $j < $FieldCountTV; $j++){
1069                             
if($this->AllowSelection == 1){
1070                                 $sel1 =
"<a href=\"{$this->ScriptFileName}?SelectedID=" . html_attr($row[$FieldCountTV]) . "\" onclick=\"document.myform.SelectedID.value='" . addslashes($row[$FieldCountTV]) . "'; document.myform.submit(); return false;\" style=\"padding:0px;\">";
1071                                 $sel2 =
"</a>";
1072                             }
else{
1073                                 $sel1 =
'';
1074                                 $sel2 =
'';
1075                             }
1076
1077                             $
this->HTML .= "<td valign=\"top\"><div>&nbsp;{$sel1}{$row[$j]}{$sel2}&nbsp;</div></td>";
1078                         }
1079                     }
1080                     $
this->HTML .= "</tr>\n";
1081                     $i++;
1082                 }
1083                 $i--;
1084             }
1085
1086             $
this->HTML = preg_replace("/<a href=\"(mailto:)?&nbsp;[^\n]*title=\"&nbsp;\"><\/a>/", '&nbsp;', $this->HTML);
1087             $
this->HTML = preg_replace("/<a [^>]*>(&nbsp;)*<\/a>/", '&nbsp;', $this->HTML);
1088             $
this->HTML = preg_replace("/<%%.*%%>/U", '&nbsp;', $this->HTML);
1089         
// end of data
1090             $
this->HTML.='<!-- tv data above -->';
1091             $
this->HTML .= "\n</tbody>";
1092
1093             
if($Print_x == ''){ // TV
1094                 $pagesMenu =
'';
1095                 
if($RecordCount > $this->RecordsPerPage){
1096                     $pagesMenuId =
"{$this->TableName}_pagesMenu";
1097                     $pagesMenu = $Translation[
'go to page'] . ' <select class="input-sm" id="' . $pagesMenuId . '" onChange="document.myform.writeAttribute(\'novalidate\', \'novalidate\'); document.myform.NoDV.value=1; document.myform.FirstRecord.value=(this.value * ' . $this->RecordsPerPage . '+1); document.myform.submit();">';
1098                     $pagesMenu .=
'</select>';
1099
1100                     $pagesMenu .=
'<script>';
1101                     $pagesMenu .=
'var lastPage = ' . (ceil($RecordCount / $this->RecordsPerPage) - 1) . ';';
1102                     $pagesMenu .=
'var currentPage = ' . (($FirstRecord - 1) / $this->RecordsPerPage) . ';';
1103                     $pagesMenu .=
'var pagesMenu = document.getElementById("' . $pagesMenuId . '");';
1104                     $pagesMenu .=
'var lump = ' . datalist_max_page_lump . ';';
1105
1106                     $pagesMenu .=
'if(lastPage <= lump * 3){';
1107                     $pagesMenu .=
' addPageNumbers(0, lastPage);';
1108                     $pagesMenu .=
'}else{';
1109                     $pagesMenu .=
' addPageNumbers(0, lump - 1);';
1110                     $pagesMenu .=
' if(currentPage < lump) addPageNumbers(lump, currentPage + lump / 2);';
1111                     $pagesMenu .=
' if(currentPage >= lump && currentPage < (lastPage - lump)){';
1112                     $pagesMenu .=
' addPageNumbers(';
1113                     $pagesMenu .=
' Math.max(currentPage - lump / 2, lump),';
1114                     $pagesMenu .=
' Math.min(currentPage + lump / 2, lastPage - lump - 1)';
1115                     $pagesMenu .=
' );';
1116                     $pagesMenu .=
' }';
1117                     $pagesMenu .=
' if(currentPage >= (lastPage - lump)) addPageNumbers(currentPage - lump / 2, lastPage - lump - 1);';
1118                     $pagesMenu .=
' addPageNumbers(lastPage - lump, lastPage);';
1119                     $pagesMenu .=
'}';
1120
1121                     $pagesMenu .=
'function addPageNumbers(fromPage, toPage){';
1122                     $pagesMenu .=
' var ellipsesIndex = 0;';
1123                     $pagesMenu .=
' if(fromPage > toPage) return;';
1124                     $pagesMenu .=
' if(fromPage > 0){';
1125                     $pagesMenu .=
' if(pagesMenu.options[pagesMenu.options.length - 1].text != fromPage){';
1126                     $pagesMenu .=
' ellipsesIndex = pagesMenu.options.length;';
1127                     $pagesMenu .=
' fromPage--;';
1128                     $pagesMenu .=
' }';
1129                     $pagesMenu .=
' }';
1130                     $pagesMenu .=
' for(i = fromPage; i <= toPage; i++){';
1131                     $pagesMenu .=
' var option = document.createElement("option");';
1132                     $pagesMenu .=
' option.text = (i + 1);';
1133                     $pagesMenu .=
' option.value = i;';
1134                     $pagesMenu .=
' if(i == currentPage){ option.selected = "selected"; }';
1135                     $pagesMenu .=
' try{';
1136                     $pagesMenu .=
' /* for IE earlier than version 8 */';
1137                     $pagesMenu .=
' pagesMenu.add(option, pagesMenu.options[null]);';
1138                     $pagesMenu .=
' }catch(e){';
1139                     $pagesMenu .=
' pagesMenu.add(option, null);';
1140                     $pagesMenu .=
' }';
1141                     $pagesMenu .=
' }';
1142                     $pagesMenu .=
' if(ellipsesIndex > 0){';
1143                     $pagesMenu .=
' pagesMenu.options[ellipsesIndex].text = " ... ";';
1144                     $pagesMenu .=
' }';
1145                     $pagesMenu .=
'}';
1146                     $pagesMenu .=
'</script>';
1147                 }
1148
1149                 $
this->HTML .= "\n\t";
1150
1151                 
if($i){ // 1 or more records found
1152                     $
this->HTML .= "<tfoot><tr><td colspan=".(count($this->ColCaption)+1).'>';
1153                         $
this->HTML .= $Translation['records x to y of z'];
1154                     $
this->HTML .= '</td></tr></tfoot>';
1155                 }
1156
1157                 
if(!$i){ // no records found
1158                     $
this->HTML .= "<tfoot><tr><td colspan=".(count($this->ColCaption)+1).'>';
1159                         $
this->HTML .= '<div class="alert alert-warning">';
1160                             $
this->HTML .= '<i class="glyphicon glyphicon-warning-sign"></i> ';
1161                             $
this->HTML .= $Translation['No matches found!'];
1162                         $
this->HTML .= '</div>';
1163                     $
this->HTML .= '</td></tr></tfoot>';
1164                 }
1165
1166             }
else{ // TVP
1167                 
if($i) $this->HTML .= "\n\t<tfoot><tr><td colspan=".(count($this->ColCaption) + 1). '>' . $Translation['records x to y of z'] . '</td></tr></tfoot>';
1168                 
if(!$i) $this->HTML .= "\n\t<tfoot><tr><td colspan=".(count($this->ColCaption) + 1). '>' . $Translation['No matches found!'] . '</td></tr></tfoot>';
1169             }
1170
1171             $
this->HTML = str_replace("<FirstRecord>", number_format($FirstRecord), $this->HTML);
1172             $
this->HTML = str_replace("<LastRecord>", number_format($i), $this->HTML);
1173             $
this->HTML = str_replace("<RecordCount>", number_format($RecordCount), $this->HTML);
1174             $tvShown=
true;
1175
1176             $
this->HTML .= "</table></div>\n";
1177
1178             
/* highlight quick search matches */
1179             
if($SearchString!='') $this->HTML .= '<script>$j(function(){ $j(".table-responsive td").mark("' . html_attr($SearchString) . '", { className: "text-warning bg-warning", diacritics: false }); })</script>';
1180
1181             
if($Print_x == '' && $i){ // TV
1182                 $
this->HTML .= '<div class="row pagination-section">';
1183                     $
this->HTML .= '<div class="col-sm-4 col-md-3 col-lg-2 vspacer-lg">';
1184                         $
this->HTML .= '<button onClick="' . $resetSelection . ' document.myform.NoDV.value = 1; return true;" type="submit" name="Previous_x" id="Previous" value="1" class="btn btn-default btn-block"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['Previous'] . '</button>';
1185                     $
this->HTML .= '</div>';
1186
1187                     $
this->HTML .= '<div class="col-sm-4 col-md-4 col-lg-2 col-md-offset-1 col-lg-offset-3 text-center vspacer-lg">';
1188                         $
this->HTML .= $pagesMenu;
1189                     $
this->HTML .= '</div>';
1190
1191                     $
this->HTML .= '<div class="col-sm-4 col-md-3 col-lg-2 col-md-offset-1 col-lg-offset-3 text-right vspacer-lg">';
1192                         $
this->HTML .= '<button onClick="'.$resetSelection.' document.myform.NoDV.value=1; return true;" type="submit" name="Next_x" id="Next" value="1" class="btn btn-default btn-block">' . $Translation['Next'] . ' <i class="glyphicon glyphicon-chevron-right"></i></button>';
1193                     $
this->HTML .= '</div>';
1194                 $
this->HTML .= '</div>';
1195             }
1196
1197             $
this->HTML .= '</div>'; // end of div.table_view
1198         }
1199         
/* that marks the end of the TV table */
1200
1201     
// hidden variables ....
1202         
foreach($this->filterers as $filterer => $caption){
1203             
if($_REQUEST['filterer_' . $filterer] != ''){
1204                 $
this->HTML .= "<input name=\"filterer_{$filterer}\" value=\"" . html_attr($_REQUEST['filterer_' . $filterer]) . "\" type=\"hidden\" />";
1205                 
break; // currently, only one filterer can be applied at a time
1206             }
1207         }
1208
1209         $
this->HTML .= '<!-- possible values for current_view: TV, TVP, DV, DVP, Filters, TVDV -->';
1210         $
this->HTML .= '<input name="current_view" id="current_view" value="' . $current_view . '" type="hidden">';
1211         $
this->HTML .= '<input name="SortField" value="' . $SortField . '" type="hidden">';
1212         $
this->HTML .= '<input name="SelectedID" value="' . html_attr($SelectedID) . '" type="hidden">';
1213         $
this->HTML .= '<input name="SelectedField" value="" type="hidden">';
1214         $
this->HTML .= '<input name="SortDirection" type="hidden" value="' . $SortDirection . '">';
1215         $
this->HTML .= '<input name="FirstRecord" type="hidden" value="' . $FirstRecord . '">';
1216         $
this->HTML .= '<input name="NoDV" type="hidden" value="">';
1217         $
this->HTML .= '<input name="PrintDV" type="hidden" value="">';
1218         
if($this->QuickSearch && !strpos($this->HTML, 'SearchString')) $this->HTML .= '<input name="SearchString" type="hidden" value="' . html_attr($SearchString) . '">';
1219     
// hidden variables: filters ...
1220         $FiltersCode =
'';
1221         
for($i = 1; $i <= (datalist_filters_count * $FiltersPerGroup); $i++){ // Number of filters allowed
1222             
if($i%$FiltersPerGroup == 1 && $i != 1 && $FilterAnd[$i] != ''){
1223                 $FiltersCode .=
"<input name=\"FilterAnd[$i]\" value=\"$FilterAnd[$i]\" type=\"hidden\">\n";
1224             }
1225             
if($FilterField[$i] != '' && $FilterOperator[$i] != '' && ($FilterValue[$i] != '' || strpos($FilterOperator[$i], 'empty'))){
1226                 
if(!strstr($FiltersCode, "<input name=\"FilterAnd[{$i}]\" value="))
1227                     $FiltersCode .=
"<input name=\"FilterAnd[{$i}]\" value=\"{$FilterAnd[$i]}\" type=\"hidden\">\n";
1228                 $FiltersCode .=
"<input name=\"FilterField[{$i}]\" value=\"{$FilterField[$i]}\" type=\"hidden\">\n";
1229                 $FiltersCode .=
"<input name=\"FilterOperator[{$i}]\" value=\"{$FilterOperator[$i]}\" type=\"hidden\">\n";
1230                 $FiltersCode .=
"<input name=\"FilterValue[{$i}]\" value=\"" . html_attr($FilterValue[$i]) . "\" type=\"hidden\">\n";
1231             }
1232         }
1233         $FiltersCode .=
"<input name=\"DisplayRecords\" value=\"$DisplayRecords\" type=\"hidden\" />";
1234         $
this->HTML .= $FiltersCode;
1235
1236     
// display details form ...
1237         
if(($this->AllowSelection || $this->AllowInsert || $this->AllowUpdate || $this->AllowDelete) && $Print_x=='' && !$PrintDV){
1238             
if(($this->SeparateDV && $this->HideTableView) || !$this->SeparateDV){
1239                 $dvCode = call_user_func(
"{$this->TableName}_form", $SelectedID, $this->AllowUpdate, (($this->HideTableView && $SelectedID) ? 0 : $this->AllowInsert), $this->AllowDelete, $this->SeparateDV, $this->TemplateDV, $this->TemplateDVP);
1240
1241                 $
this->HTML .= "\n\t<div class=\"col-xs-12 detail_view {$this->DVClasses}\">{$tv_dv_separator}<div class=\"panel panel-default\">{$dvCode}</div></div>";
1242                 $
this->HTML .= ($this->SeparateDV ? '<input name="SearchString" value="' . html_attr($SearchString) . '" type="hidden">' : '');
1243                 
if($dvCode){
1244                     $
this->ContentType = 'detailview';
1245                     $dvShown =
true;
1246                 }
1247             }
1248         }
1249
1250     
// display multiple printable detail views
1251         
if($PrintDV){
1252             $dvCode =
'';
1253             $_REQUEST[
'dvprint_x'] = 1;
1254
1255             
// hidden vars
1256             
foreach($this->filterers as $filterer => $caption){
1257                 
if($_REQUEST['filterer_' . $filterer] != ''){
1258                     $
this->HTML .= "<input name=\"filterer_{$filterer}\" value=\"" . html_attr($_REQUEST['filterer_' . $filterer]) . "\" type=\"hidden\" />";
1259                     
break; // currently, only one filterer can be applied at a time
1260                 }
1261             }
1262
1263             
// count selected records
1264             $selectedRecords =
0;
1265             
if(is_array($_REQUEST['record_selector'])) foreach($_REQUEST['record_selector'] as $id){
1266                 $selectedRecords++;
1267                 $
this->HTML .= '<input type="hidden" name="record_selector[]" value="' . html_attr($id) . '">'."\n";
1268             }
1269
1270             
if($selectedRecords && $selectedRecords <= datalist_max_records_dv_print){ // if records selected > {datalist_max_records_dv_print} don't show DV preview to avoid db performance issues.
1271                 
foreach($_REQUEST['record_selector'] as $id){
1272                     $dvCode .= call_user_func($
this->TableName . '_form', $id, 0, 0, 0, 1, $this->TemplateDV, $this->TemplateDVP);
1273                 }
1274
1275                 
if($dvCode!=''){
1276                     $dvCode = preg_replace(
'/<input .*?type="?image"?.*?>/', '', $dvCode);
1277                     $
this->HTML .= $dvCode;
1278                 }
1279             }
else{
1280                 $
this->HTML .= error_message($Translation['Maximum records allowed to enable this feature is'] . ' ' . datalist_max_records_dv_print);
1281                 $
this->HTML .= '<input type="submit" class="print-button" value="'.$Translation['Print Preview Table View'].'">';
1282             }
1283         }
1284
1285         $
this->HTML .= "</div></form>";
1286         $
this->HTML .= '</div><div class="col-xs-1 md-hidden lg-hidden"></div></div>';
1287
1288         
// $this->HTML .= '<font face="garamond">'.html_attr($tvQuery).'</font>'; // uncomment this line for debugging the table view query
1289
1290         
if($dvShown && $tvShown) $this->ContentType='tableview+detailview';
1291         
if($dvprint_x!='') $this->ContentType='print-detailview';
1292         
if($Print_x!='') $this->ContentType='print-tableview';
1293         
if($PrintDV!='') $this->ContentType='print-detailview';
1294
1295         
// call detail view javascript hook file if found
1296         $dvJSHooksFile=dirname(__FILE__).
'/hooks/'.$this->TableName.'-dv.js';
1297         
if(is_file($dvJSHooksFile) && ($this->ContentType=='detailview' || $this->ContentType=='tableview+detailview')){
1298             $
this->HTML.="\n<script src=\"hooks/{$this->TableName}-dv.js\"></script>\n";
1299         }
1300     }
1301 }


Gõ tìm kiếm nhanh...